<?php

namespace Yjius\openapi\dingtalk;

use Yjius\common\CurlHelper;
use Yjius\common\Debug;
use Yjius\common\ToolsHelper;
use Yii;

/**
 * 钉钉应用基础封装
 * //    private $base_url = 'https://oapi.dingtalk.com/';
 * //    private $new_base_url = 'https://api.dingtalk.com/'; // 新版服务端api域名
 * Class DingTalkBase
 * @package common\extensions
 * @date  2022/4/28 16:36
 */
class DingTalkBase
{
    //应用参数
    private $appKey = null;
    private $appSecret = null;
    private $agentId = null;
    private $corpId = null;

    //最外层初始化时，YII_ENV 可以选择不同的应用
    public function __construct($config = [])
    {
        //裁入配置
        $this->appKey = $config['app_key'] ?: '';
        $this->appSecret = $config['app_secret'] ?: '';
        $this->agentId = $config['agent_id'] ?: '';
        $this->corpId = $config['corp_id'] ?: '';
        if (empty($this->appKey) || empty($this->appSecret) || empty($this->agentId) || empty($this->corpId)) {
            throw new \Exception("载入配置错误，请检查参数是否正确");
        }
    }

    /**
     * 发送工作通知
     *
     * 文本消息 $msgType = "text" $msgData = ['content'=>"发送的消息内容"]
     * 链接消息 $msgType = "link" $msgData = [
     *                                      'linkType'=>'link_work_platform',//link_pc_slide、link_work_platform（默认）、link_eapp
     *                                      'url'=>"http://s.dingtalk.com/market/dingtalk/error_code.php",
     *                                      "picUrl"=>"@lALOACZwe2Rk",
     *                                      "title"=>"测试",
     *                                      "text"=>"测试"
     *                                      ]
     * 图片消息 $msgType = "image" $msgData = ['media_id'=>"@lADOADmaWMzazQKA"]
     * 文件消息 $msgType = "file" $msgData = ['media_id'=>"MEDIA_ID"]
     * 语音消息 $msgType = "voice" $msgData = ['media_id'=>"MEDIA_ID",'duration'=>50]
     *
     * $userIdsStr 用户ID列表，字符串逗号链接
     * $deptIdsStr 按部门去发消息，字符串逗号链接
     * $toAllUser 是否全员发送消息  一般默认为false，false时，用户和部门必传一个。
     * @return null
     */
    public function sendWorkMsg($msgType = "text", $msgData = [], $userIdsStr = "", $deptIdsStr = "", $toAllUser = false)
    {
        // 非正式环境 关闭通知
        if (YII_ENV != "pro") {
            if (!empty(getenv("DEV_DIGITAL_USERIDLIST"))) {
                $userIdsStr = getenv("DEV_DIGITAL_USERIDLIST");
            } else {
                return false;
            }
            $deptIdsStr = '';
            $toAllUser = false;
        }
        if (empty($toAllUser) && empty($userIdsStr) && empty($deptIdsStr)) {
            throw new \Exception("请选择发送工作通知的用户或部门群体");
        }
        switch ($msgType) {
            //文本消息
            case "text":
                if (!isset($msgData['content'])) {
                    throw new \Exception("文本消息请输入消息通知内容");
                }
                $msg = [
                    'msgtype' => "text",
                    'text' => $msgData,
                ];
                break;
            //图片消息
            case "image":
                if (!isset($msgData['media_id'])) {
                    throw new \Exception("图片消息请输入消息通知内容");
                }
                $msg = [
                    'msgtype' => "image",
                    'image' => $msgData,
                ];
                break;
            //语音消息
            case "voice":
                if (!isset($msgData['media_id']) || !isset($msgData['duration'])) {
                    throw new \Exception("语音消息请输入消息通知内容");
                }
                $msg = [
                    'msgtype' => "voice",
                    'voice' => $msgData,
                ];
                break;
            //文件消息
            case "file":
                if (!isset($msgData['media_id'])) {
                    throw new \Exception("文本消息请输入消息通知内容");
                }
                $msg = [
                    'msgtype' => "file",
                    'file' => $msgData,
                ];
                break;
            //链接消息
            case "link":
                if (!isset($msgData['linkType'])) {
                    throw new \Exception("链接消息请输入链接打开类型");
                }
                switch ($msgData['linkType']) {
                    case 'link_pc_slide': //消息链接在PC端侧边栏打开
                        $msg = [
                            'msgtype' => "link",
                            'link' => [
                                'messageUrl' => 'dingtalk://dingtalkclient/page/link?pc_slide=true&url=' . urlencode($msgData['url']),
                                'picUrl' => '@lALOACZwe2Rk',
                                'title' => $msgData['title'],
                                'text' => $msgData['text'],
                            ],
                        ];
                        break;
                    case 'link_work_platform': //消息链接在PC端工作台打开（建议默认）
                        $msg = [
                            'msgtype' => "link",
                            'link' => [
                                'messageUrl' => 'dingtalk://dingtalkclient/action/openapp?corpid=' . $this->corpId . '&container_type=work_platform&app_id=0_' . $this->agentId . '&redirect_type=jump&redirect_url=' . urlencode($msgData['url']),
                                'picUrl' => '@lALOACZwe2Rk',
                                'title' => $msgData['title'],
                                'text' => $msgData['text'],
                            ],
                        ];
                        break;
                    case 'link_eapp': //消息链接在小程序打开 仅支持小程序应用才能支持
                        $msg = [
                            'msgtype' => "link",
                            'link' => [
                                'messageUrl' => $msgData['url'],
                                'picUrl' => '@lALOACZwe2Rk',
                                'title' => $msgData['title'],
                                'text' => $msgData['text'],
                            ],
                        ];
                        break;
                    default:
                        throw new \Exception("请选择正确的链接打开类型");
                        break;
                }
                break;
            //其他未知类型
            default:
                throw new \Exception("请选择正确的工作通知类型或当前类型暂不支持");
                break;
        }
        //组合数据发送工作通知
        $data = [
            'agent_id' => $this->agentId,
            'msg' => $msg,
        ];
        if (!empty($userIdsStr)) {
            $data['userid_list'] = $userIdsStr;
        }
        if (!empty($deptIdsStr)) {
            $data['dept_id_list'] = $deptIdsStr;
        }
        if (!empty($toAllUser)) {
            $data['to_all_user'] = $toAllUser;
        }
        $request_url = "https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2";
        $access_token = $this->getAccessToken();
        $params = [
            'access_token' => $access_token
        ];
        $json_data = json_encode($data, JSON_UNESCAPED_UNICODE);
        $headers = ['Content-Type: application/json', 'Content-Length: ' . strlen($json_data)];
        $res = CurlHelper::httpRequest($request_url, $headers, 'POST', $params, $json_data);
        $res = json_decode($res, true);
        if (isset($res['errcode']) && $res['errcode'] != 0) {
            throw new \Exception($res['errmsg']);
        }
        return $res;
    }


    /**
     * 获取钉钉access_token
     * access_token
     * @return mixed
     */
    public function getAccessToken()
    {
        $res = CurlHelper::httpRequest("https://oapi.dingtalk.com/gettoken", [], 'GET', [
            'appkey' => $this->appKey,
            'appsecret' => $this->appSecret,
        ]);
        $res = json_decode($res, true);
        if (isset($res['errcode']) && $res['errcode'] != 0) {
            throw new \Exception($res['errmsg']);
        }
        return $res['access_token'];
    }


    /**
     * 签名配置
     */
    public function getSignConfig($url)
    {
        $ticket = $this->getTicket();
        $nonceStr = ToolsHelper::random(10);
        $timeStamp = time();
        $signature = self::sign($ticket, $nonceStr, $timeStamp, $url);
        return [
            'url' => $url,
            'nonceStr' => $nonceStr,
            'agentId' => $this->agentId,
            'timeStamp' => $timeStamp,
            'corpId' => $this->corpId,
            'suite_key' => "",
            'signature' => $signature
        ];
    }


    /**
     * Purpose: 获取企业架构信息
     * Author:yingjiusheng@gsdata.cn
     * @date 2022/4/18 16:32
     */
    public function getDepartList($dept_id = 1)
    {
        $access_token = $this->getAccessToken();
        $request_url = "https://oapi.dingtalk.com/topapi/v2/department/listsub";
        $params = [
            'access_token' => $access_token
        ];
        $data = [
            'language' => 'zh_CN',
            'dept_id' => $dept_id
        ];
        $json_data = json_encode($data, JSON_UNESCAPED_UNICODE);
        $headers = ['Content-Type: application/json', 'Content-Length: ' . strlen($json_data)];
        $res = CurlHelper::httpRequest($request_url, $headers, 'POST', $params, $json_data);
        $res = json_decode($res, true);
        if (isset($res['errcode']) && $res['errcode'] != 0) {
            throw new \Exception($res['errmsg']);
        }
        return $res['result'];
    }

    /**
     * Purpose: 获取企业部门详情
     * Author:yingjiusheng@gsdata.cn
     * @date 2022/4/18 17:35
     */
    public function getDepartInfo($dept_id = 1)
    {
        $access_token = $this->getAccessToken();
        $request_url = "https://oapi.dingtalk.com/topapi/v2/department/get";
        $params = [
            'access_token' => $access_token
        ];
        $data = [
            'language' => 'zh_CN',
            'dept_id' => $dept_id
        ];
        $json_data = json_encode($data, JSON_UNESCAPED_UNICODE);
        $headers = ['Content-Type: application/json', 'Content-Length: ' . strlen($json_data)];
        $res = CurlHelper::httpRequest($request_url, $headers, 'POST', $params, $json_data);
        $res = json_decode($res, true);
        if (isset($res['errcode']) && $res['errcode'] != 0) {
            throw new \Exception($res['errmsg']);
        }
        return $res['result'];
    }

    /**
     * Purpose: 获取部门架构下的用户列表
     * Author:yingjiusheng@gsdata.cn
     * @date 2022/4/18 17:22
     */
    public function getDepartUserList($dept_id = 1)
    {
        $access_token = $this->getAccessToken();
        $request_url = "https://oapi.dingtalk.com/topapi/user/listid";
        $params = [
            'access_token' => $access_token
        ];
        $data = [
            'dept_id' => $dept_id
        ];
        $json_data = json_encode($data, JSON_UNESCAPED_UNICODE);
        $headers = ['Content-Type: application/json', 'Content-Length: ' . strlen($json_data)];
        $res = CurlHelper::httpRequest($request_url, $headers, 'POST', $params, $json_data);
        $res = json_decode($res, true);
        if (isset($res['errcode']) && $res['errcode'] != 0) {
            throw new \Exception($res['errmsg']);
        }
        return $res['result'];
    }

    /**
     * Purpose: 根据code获取用户ID
     * Author:yingjiusheng@gsdata.cn
     * @date 2022/4/18 17:53
     */
    public function getUserIdByCode($code)
    {
        //基础信息
        $token = $this->getAccessToken();
        $user_base_res = CurlHelper::httpRequest("https://oapi.dingtalk.com/topapi/v2/user/getuserinfo", [], 'GET', [
            'access_token' => $token,
            'code' => $code,
        ]);
        $res = json_decode($user_base_res, true);
        if (isset($res['errcode']) && $res['errcode'] != 0) {
            throw new \Exception($res['errmsg']);
        }
        return $res['result'];
    }

    /**
     * Purpose:
     * Author:yingjiusheng@gsdata.cn
     * @date 2022/4/18 17:44
     */
    public function getUserInfoByUserId($userid)
    {
        $access_token = $this->getAccessToken();
        $request_url = "https://oapi.dingtalk.com/topapi/v2/user/get";
        $params = [
            'access_token' => $access_token
        ];
        $data = [
            'userid' => $userid,
            'language' => "zh_CN"
        ];
        $json_data = json_encode($data, JSON_UNESCAPED_UNICODE);
        $headers = ['Content-Type: application/json', 'Content-Length: ' . strlen($json_data)];
        $res = CurlHelper::httpRequest($request_url, $headers, 'POST', $params, $json_data);
        $res = json_decode($res, true);
        if (isset($res['errcode']) && $res['errcode'] != 0) {
            throw new \Exception($res['errmsg']);
        }
        return $res['result'];
    }

    /**
     * Purpose: 获取所有用户列表
     * 注：此接口应用均没有权限
     * Author:yingjiusheng@gsdata.cn
     * @date 2022/4/18 18:24
     */
    public function getUserList($statusStr = "2,3,5,-1", $offset = 0, $size = 50)
    {
        $access_token = $this->getAccessToken();
        $request_url = "https://oapi.dingtalk.com/topapi/smartwork/hrm/employee/queryonjob";
        $params = [
            'access_token' => $access_token
        ];
        $data = [
            'language' => 'zh_CN',
            'status_list' => $statusStr,
            'offset' => $offset,
            'size' => $size
        ];
        $json_data = json_encode($data, JSON_UNESCAPED_UNICODE);
        $headers = ['Content-Type: application/json', 'Content-Length: ' . strlen($json_data)];
        $res = CurlHelper::httpRequest($request_url, $headers, 'POST', $params, $json_data);
        $res = json_decode($res, true);
        if (isset($res['errcode']) && $res['errcode'] != 0) {
            throw new \Exception($res['errmsg']);
        }
        return $res['result'];
    }


    // 解决系统函数pathinfo 在linux解析中文出错的问题
    private function path_info($file_path)
    {
        $path_parts = [];
        $path_parts ['dirname'] = rtrim(substr($file_path, 0, strrpos($file_path, '/')), "/") . "/";
        $path_parts ['basename'] = ltrim(substr($file_path, strrpos($file_path, '/')), "/");
        $path_parts ['extension'] = substr(strrchr($file_path, '.'), 1);
        $path_parts ['filename'] = ltrim(substr($path_parts ['basename'], 0,
            strrpos($path_parts ['basename'], '.')), "/");
        return $path_parts;
    }

    /**
     * Purpose: 保存文件到钉盘
     * 使用时，分片上传需测试！！！！！！
     * Author:yingjiusheng@gsdata.cn
     * @date 2022/4/28 16:14
     */
    public function saveFile($url)
    {
        // 先读取远程文件保存到本地
        $file_info = $this->path_info($url);
        $file_name = $file_info['basename'];
        $save_path = Yii::$app->basePath;
        $local_file = $save_path . '/' . $file_name;
        $url = rtrim($file_info['dirname'], '/') . '/' . rawurlencode($file_info['basename']); // 对中文编码
        $file = @file_get_contents($url);
        if (empty($file)) {
            throw new \Exception("附件内容不能为空或者附件链接错误");
        }
        file_put_contents($local_file, $file);
        $file_size = filesize($local_file);

        //准备上传钉盘
        $access_token = $this->getAccessToken();

        // 文件小于8M则直接上传
        if ($file_size <= 1024 * 1024 * 8) {
            $request_url = "https://oapi.dingtalk.com/file/upload/single";
            $params = [
                'access_token' => $access_token,
                'file_size' => $file_size,
                'agent_id' => $this->agentId,
            ];
            $data['file'] = new \CURLFile($local_file);
            $res = CurlHelper::httpRequest($request_url, [], 'POST', $params, $data, true);
            $res = json_decode($res, true);
            if ($res['errcode'] != 0) {
                throw new \Exception("上传文件失败");
            }
            $media_id = $res['media_id'];
            unlink($local_file);
            return ['media_id' => $media_id];
        } else {
            // 大于8M则分块上传
            // 1.开启上传事物
            $chunk_numbers = ceil($file_size / (1024 * 1024 * 8));
            $start_transaction_url = "https://oapi.dingtalk.com/file/upload/transaction";
            $start_transaction_params = [
                'access_token' => $access_token,
                'file_size' => $file_size,
                'agent_id' => $this->agentId,
                'chunk_numbers' => $chunk_numbers,
            ];
            $start_res = CurlHelper::httpRequest($start_transaction_url, [], 'GET', $start_transaction_params);
            $start_res = json_decode($start_res, true);

            // 2.分批上传文件
            if ($start_res['errcode'] == 0) {
                $upload_id = $start_res['upload_id'];
                $chunk_url = "https://oapi.dingtalk.com/file/upload/chunk";
                $chunk_params = [
                    'access_token' => $access_token,
                    'upload_id' => $upload_id,
                    'agent_id' => $this->agentId,
                ];
                $i = 1; //分割的块编号
                $fp = fopen($local_file, "rb"); //要分割的文件
                while (!feof($fp)) {
                    $tmp_file = $i . '.' . $file_info['extension'];
                    $handle = fopen($tmp_file, "wb");
                    fwrite($handle, fread($fp, 1024 * 1024 * 8));//切割的块大小 8m
                    // 上传文件块
                    $chunk_params = array_merge($chunk_params, ['chunk_sequence' => $i]);
                    $data['file'] = new \CURLFile($tmp_file);

                    $chunk_res = CurlHelper::httpRequest($chunk_url, [], 'POST', $chunk_params, $data, true);
                    $chunk_res = json_decode($chunk_res, true);
                    if ($chunk_res['errcode'] != 0) {
                        throw new \Exception("上传文件失败");
                    }
                    fclose($handle);
                    unlink($tmp_file);
                    unset($handle);
                    $i++;
                }
                fclose($fp);

                // 3.提交上传事物
                $end_transaction_url = "https://oapi.dingtalk.com/file/upload/transaction";
                $end_transaction_params = array_merge($start_transaction_params, ['upload_id' => $upload_id]);
                $end_res = CurlHelper::httpRequest($end_transaction_url, [], 'GET', $end_transaction_params);
                $end_res = json_decode($end_res, true);
                if ($end_res['errcode'] != 0) {
                    throw new \Exception("提交上传事物失败");
                }
                $media_id = $end_res['media_id'];
                unlink($local_file);
                return ['media_id' => $media_id];
            } else {
                throw new \Exception("开启上传事物失败");
            }
        }
    }


    /**
     * Purpose: 获取某一次审批单详情
     * Author:yingjiusheng@gsdata.cn
     * @date 2022/4/28 16:42
     */
    public function getProcessInfo($processInstanceId)
    {
        $access_token = $this->getAccessToken();
        $request_url = "https://oapi.dingtalk.com/topapi/processinstance/get";
        $params = [
            'access_token' => $access_token
        ];
        $data = [
            'process_instance_id' => $processInstanceId,
        ];
        $json_data = json_encode($data, JSON_UNESCAPED_UNICODE);
        $headers = ['Content-Type: application/json', 'Content-Length: ' . strlen($json_data)];
        $res = CurlHelper::httpRequest($request_url, $headers, 'POST', $params, $json_data);
        $res = json_decode($res, true);
        if (isset($res['errcode']) && $res['errcode'] != 0) {
            throw new \Exception($res['errmsg']);
        }
        return $res;
    }


    /**
     * Purpose: 获取审批模板code 一次获取即可
     * 根据模板名称查询模板code
     * Author:yingjiusheng@gsdata.cn
     * @date 2022/4/28 16:53
     */
    public function getProcessCode($name)
    {
        $access_token = $this->getAccessToken();
        $request_url = "https://oapi.dingtalk.com/topapi/process/get_by_name";
        $params = [
            'access_token' => $access_token
        ];
        $data = [
            'name' => $name,
        ];
        $json_data = json_encode($data, JSON_UNESCAPED_UNICODE);
        $headers = ['Content-Type: application/json', 'Content-Length: ' . strlen($json_data)];
        $res = CurlHelper::httpRequest($request_url, $headers, 'POST', $params, $json_data);
        $res = json_decode($res, true);
        if (isset($res['errcode']) && $res['errcode'] != 0) {
            throw new \Exception($res['errmsg']);
        }
        return $res;
    }


    /**
     * Purpose: 获取审批模板表单scheme
     * Author:yingjiusheng@gsdata.cn
     * @date 2022/4/28 16:59
     */
    public function getProcessScheme($processCode)
    {
        $access_token = $this->getAccessToken();
        $request_url = "https://api.dingtalk.com/v1.0/workflow/forms/schemas/processCodes";
        $params = [
            'processCode' => $processCode,
        ];
        $headers = ["Content-Type: application/json", "x-acs-dingtalk-access-token: $access_token"];
        $res = CurlHelper::httpRequest($request_url, $headers, 'GET', $params);
        $res = json_decode($res, true);
        if (isset($res['errcode']) && $res['errcode'] != 0) {
            throw new \Exception($res['errmsg']);
        }
        return $res;
    }

    /**
     * Purpose: 获取审批实例ID列表
     * 获取当前审批code下有多少实例单
     * Author:yingjiusheng@gsdata.cn
     * @date 2022/4/28 16:48
     * $processCode
     * $startTime
     * $endTime
     * $size     //每页数量
     * $cursor  //分页查询的游标，最开始传0，后续传返回参数中的next_cursor值。
     * $useridStr  //发起人列表 逗号链接
     */
    public function getProcessInstance($processCode, $startDatetime = '', $endDatetime = '', $size = 10, $cursor = 0, $useridStr = '')
    {
        if (empty($processCode)) {
            throw new \Exception("请先传入审批单code");
        }
        //默认今天
        if (empty($startDatetime)) {
            $startDatetime = date('Y-m-d 00:00:00');
        }
        $stime = strtotime($startDatetime) * 1000;
        if (!empty($endDatetime)) {
            $etime = strtotime($endDatetime) * 1000;
        }
        $access_token = $this->getAccessToken();
        $request_url = "https://oapi.dingtalk.com/topapi/processinstance/listids";
        $params = [
            'access_token' => $access_token
        ];
        $data = [
            'start_time' => $stime,
            'size' => $size,
            'cursor' => $cursor,
            'process_code' => $processCode,
        ];
        if (!empty($etime)) {
            $data['end_time'] = $etime;
        }
        if (!empty($useridStr)) {
            $data['userid_list'] = $useridStr;
        }

        $json_data = json_encode($data, JSON_UNESCAPED_UNICODE);
        $headers = ['Content-Type: application/json', 'Content-Length: ' . strlen($json_data)];
        $res = CurlHelper::httpRequest($request_url, $headers, 'POST', $params, $json_data);
        $res = json_decode($res, true);
        if (isset($res['errcode']) && $res['errcode'] != 0) {
            throw new \Exception($res['errmsg']);
        }
        return $res;
    }


    /**
     * Purpose: 发起审批实例
     * 待调试后，暂不可使用！！！！！！！
     * Author:yingjiusheng@gsdata.cn
     * @date 2022/4/28 17:19
     */
    public function approvalProcess()
    {
        $access_token = $this->getAccessToken();
        $request_url = "https://oapi.dingtalk.com/topapi/processinstance/create";
        $post_data = [
            'originator_user_id' => '505944172721263954', // 安规清博 LZY 测试用账号
            'process_code' => 'PROC-8C547219-0EB3-491A-98E6-ACA36FC7ECBC',
            'dept_id' => '122587086',
            'agent_id' => '1131747287',
            'form_component_values' => [
                [
                    'name' => '客户名称',
                    'value' => '合肥工业大学2',
                ],
                [
                    'name' => '多行输入框',
                    'value' => '多行输入框测试2',
                ],
                [
                    'name' => '项目名称',
                    'value' => '合肥工业大学大屏2',
                ],
                [
                    'name' => '评估发起时间',
                    'value' => '2022-03-17',
                ],
                [
                    'name' => '项目阶段',
                    'value' => '初始2',
                ],
                [
                    'name' => '附件',
                    'value' => '[{"spaceId": "742149823", "fileName": "湖南星辰在线新媒体有限公司合同2021.docx", "fileSize": "22182", "fileType": "docx", "fileId": "34819726100"}]',
                ]
            ],
        ];
        $params = [
            'access_token' => $access_token
        ];
        $json_data = json_encode($post_data, JSON_UNESCAPED_UNICODE);
        $headers = ["Content-Type: application/json", 'Content-Length: ' . strlen($json_data)];
        $res = CurlHelper::httpRequest($request_url, $headers, 'POST', $params, $json_data);
        $res = json_decode($res, true);
        if (isset($res['errcode']) && $res['errcode'] != 0) {
            throw new \Exception($res['errmsg']);
        }
        return $res['result'];
    }


    /**
     * Purpose: 发送钉盘文件到指定用户
     * Author:yingjiusheng@gsdata.cn
     * @date 2022/4/28 16:33
     */
    public function sendFileToUser($userid, $media_id, $file_name)
    {
        $access_token = $this->getAccessToken();
        $request_url = "https://oapi.dingtalk.com/cspace/add_to_single_chat";
        $params = [
            'access_token' => $access_token,
            'media_id' => $media_id,
            'file_name' => $file_name,
            'userid' => $userid,
            'agent_id' => $this->agentId,
        ];
        $res = CurlHelper::httpRequest($request_url, [], 'POST', $params);
        $res = json_decode($res, true);
        return $res;
    }

    /**
     * @param String $ticket
     * @param String $nonceStr //随机字符串
     * @param int $timeStamp //当前时间戳
     * @param String $url //调用dd.config的当前页面URL
     * @return string
     */
    private static function sign($ticket, $nonceStr, $timeStamp, $url)
    {
        return sha1("jsapi_ticket={$ticket}&noncestr={$nonceStr}&timestamp={$timeStamp}&url={$url}");
    }

    /**
     * 获取 js api_ticket
     */
    private function getTicket()
    {
        $token = $this->getAccessToken();
        $res = CurlHelper::httpRequest("https://oapi.dingtalk.com/get_jsapi_ticket", [], 'GET', [
            'access_token' => $token
        ]);
        $res = json_decode($res, true);
        if (isset($res['errcode']) && $res['errcode'] != 0) {
            throw new \Exception($res['errmsg']);
        }
        return $res['ticket'];
    }
}
